#pragma once
#include <common.hpp>

namespace zzz {
template <typename T>
class zVar {
public:
  zVar(const T &v):v_(v){}
  friend inline ostream& operator<<(ostream& os, const zVar<T> &me) {
    os<<me.v_;
    return os;
  }
private:
  const T &v_;
};

//Use zout<<GetzVar(X) will output x only
//Use zout<<ZVAR(X) will output {X:x_value}

template<typename T>
inline const zVar<T> GetzVar(const T &v) {return zVar<T>(v);}

#define ZVAR(x) "{"<<#x<<"="<<GetzVar(x)<<"}"
#define ZVAR2(name, x) "{"<<name<<"="<<GetzVar(x)<<"}"

template <typename T1, typename T2>
class zVar<std::pair<T1, T2> > {
public:
  zVar(const std::pair<T1, T2> &v):v_(v){}
  friend inline ostream& operator<<(ostream& os, const zVar<std::pair<T1, T2> > &me) {
    os<<GetzVar(me.v_.first)<<', '<<GetzVar(me.v_.second);
    return os;
  }
private:
  const std::pair<T1, T2> &v_;
};

#define STL_CONTAINER_ZVAR(CONTAINER) \
template <typename T>\
class zVar< CONTAINER<T> > {\
public:\
  zVar(const CONTAINER<T> &v):v_(v){}\
  friend inline ostream& operator<<(ostream& os, const zVar< CONTAINER<T> > &me) {\
    os<<ZVAR2("Size", me.v_.size());\
    int i;\
    os << '[';\
    CONTAINER<T>::const_iterator vi;\
    for (i = 0, vi =me.v_.begin(); i < 10 && vi!=me.v_.end(); ++vi, ++i)\
      os << '<' << GetzVar(*vi) << '>';\
    if (i == 0 && vi != me.v_.end())\
      os << "<...>";\
    os << ']';\
    return os;\
  }\
private:\
  const CONTAINER<T> &v_;\
};

STL_CONTAINER_ZVAR(std::vector);
STL_CONTAINER_ZVAR(std::list);
STL_CONTAINER_ZVAR(std::deque);
STL_CONTAINER_ZVAR(std::stack);
STL_CONTAINER_ZVAR(std::queue);
STL_CONTAINER_ZVAR(std::set);
STL_CONTAINER_ZVAR(std::multiset);
};  // namespace zzz